<?php

namespace app\admin\service\common;

use app\admin\annotation\common\Auth;
use app\common\Constants;
use app\common\ErrorCode;
use app\common\exception\BusinessException;
use think\facade\Log;

class AuthCheckService
{
    public static function check($controller, $action, $userPermissions)
    {
        $controllerClass = "app\\admin\\controller\\" . str_replace('.', '\\', $controller);

        if (!class_exists($controllerClass)) {
            return; // 控制器不存在，跳过
        }

        $reflectionClass = new \ReflectionClass($controllerClass);

        // 1. 先检查方法权限
        $methodPassed = false;
        if ($reflectionClass->hasMethod($action)) {
            $reflectionMethod = $reflectionClass->getMethod($action);
            $methodAttributes = $reflectionMethod->getAttributes(Auth::class);
            foreach ($methodAttributes as $attribute) {
                $auth = $attribute->newInstance();
                // trace($auth,'适配方法权限');
                if (self::checkSingleSet($auth->permissions, $userPermissions, $auth->mode)) {
                    trace($auth->permissions,'适配方法权限');
                    $methodPassed = true; // 方法权限通过
                    break;
                } else {
                    trace('权限不足');
                    throw new  BusinessException(Constants::E_COMMON_FORBIDDEN,ErrorCode::FORBIDDEN);
                }
            }
        }

        // 2. 方法权限通过则直接返回
        if ($methodPassed) return;

        // 3. 方法权限未通过，检查类权限
        $classAttributes = $reflectionClass->getAttributes(Auth::class);
        foreach ($classAttributes as $attribute) {
            $auth = $attribute->newInstance();
            // trace($auth,'适配类权限');
            if (self::checkSingleSet($auth->permissions, $userPermissions, $auth->mode)) {
                trace($auth->permissions,'适配类权限');
                return;
            } else {
                trace('权限不足');
                throw new BusinessException(Constants::E_COMMON_FORBIDDEN,ErrorCode::FORBIDDEN);
            }
        }

        // 4. 方法有权限要求但未通过，或者 有类权限要求但未通过 则抛出异常
        if (!empty($methodAttributes) || !empty($classAttributes)) {
            throw new BusinessException(Constants::E_COMMON_FORBIDDEN, ErrorCode::FORBIDDEN);
        }


    }

    private static function checkSingleSet($required, $userPermissions, $mode): bool
    {
        trace(json_encode($required), "所需权限");
        trace(json_encode($userPermissions), "用户权限");
        trace($mode, "计算模式");


        if (empty($required)) return true;

        $matchedCount = 0;
        foreach ($required as $reqPerm) {
            trace($reqPerm, "所需权限");
            $isMatched = false;
            foreach ($userPermissions as $userPerm) {
                // trace($userPerm, "用户权限");
                // 1. 精确匹配
                if ($reqPerm === $userPerm) {
                    trace($reqPerm, "精确匹配");
                    $isMatched = true;
                    break;
                }
                // 2. 通配符匹配 ('*')
                if (str_ends_with($userPerm, ":*")) {
                    $prefix = substr($userPerm, 0, -1); // 获取通配符 '*' 之前的前缀, e.g., "admin:lang:"
                    if (str_starts_with($reqPerm, $prefix)) {
                        trace($reqPerm, "通配符匹配");
                        $isMatched = true;
                        break;
                    }
                }
            }
            if ($isMatched) {
                $matchedCount++;
            }
        }

        if ($mode === 'and') {
            return $matchedCount === count($required);
        } else { // mode === 'or'
            return $matchedCount > 0;
        }

    }
}